package com.netease.nim.demo.session.activity;

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netease.nim.demo.base.YXBaseActivity;
import com.netease.nim.demo.common.adapter.TAdapterDelegate;
import com.netease.nim.demo.common.adapter.TViewHolder;
import com.netease.nim.demo.common.infra.Handlers;
import com.netease.nim.demo.common.ui.dialog.EasyAlertDialog;
import com.netease.nim.demo.common.ui.dialog.EasyAlertDialogHelper;
import com.netease.nim.demo.common.ui.listview.AutoRefreshListView;
import com.netease.nim.demo.common.ui.listview.ListViewUtil;
import com.netease.nim.demo.common.ui.listview.MessageListView;
import com.netease.nim.demo.contact.cache.ContactDataCache;
import com.netease.nim.demo.contact.protocol.ContactHttpClient;
import com.netease.nim.demo.main.model.Extras;
import com.netease.nim.demo.session.adapter.MsgAdapter;
import com.netease.nim.demo.session.model.MsgListItem;
import com.netease.nim.demo.session.model.MsgViewHolderType;
import com.netease.nim.demo.session.viewholder.MsgViewHolder;
import com.netease.nim.demo.session.viewholder.MsgViewHolderPictureLeft;
import com.netease.nim.demo.session.viewholder.MsgViewHolderPictureRight;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.AttachmentProgress;
import com.netease.nimlib.sdk.msg.model.CustomNotification;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.shwread.android.qysw10000227.R;

import java.io.File;
import java.util.ArrayList;
import java.util.List;


/**
 * 聊天界面抽象类（封装数据的获取与发送）
 * <p/>
 * Created by huangjun on 2015/2/1.
 */
public abstract class AbsBaseMessageActivity
        extends
        YXBaseActivity
        implements
        TAdapterDelegate,
        AutoRefreshListView.OnRefreshListener,
        MessageListView.OnListViewEventListener,
        MsgViewHolder.ViewHolderEventListener
{
	
	public static final int			P2P_REQUEST_CODE		= 10000;
	protected static final String	TAG						= "MessageActivity";
	protected static final int		LOAD_MESSAGE_COUNT		= 20;
	public static List<MsgListItem>	totalItems				= new ArrayList<MsgListItem>();
	// context
	protected Context				context;
	protected Handler				uiHandler;
	protected ContactHttpClient		contactHttpClient;
	protected String				receiverid;											   // p2p对方Account或者群id
	// view
	protected View					rootView;
	protected MessageListView		messageListView;
	//title
	protected Button				backBtn;
	protected TextView				titleTView;
	protected ImageView groupBtn;
	// adapter
	protected MsgAdapter			adapter;
	protected MsgListItem			lastShowTimeItem;									   // 用于消息时间显示,判断和上条消息间的时间间隔
	// db
	protected boolean				firstLoadMessageHistory	= true;
	//
	TitleView						titleView;
	Observer<List<IMMessage>>	 incomingMessageObserver	= new Observer<List<IMMessage>>()
	                                                        {
		                                                        @Override
		                                                        public void onEvent(List<IMMessage> messages) {
			                                                        if (messages == null || messages.isEmpty()) { return; }

			                                                        boolean needScrollToBottom = ListViewUtil.isLastMessageVisible(messageListView);
			                                                        boolean needRefresh = false;
			                                                        List<MsgListItem> addedListItems = new ArrayList<MsgListItem>(messages.size());
			                                                        for (IMMessage message : messages)
			                                                        {
				                                                        if (message.getSessionId() == null) { return; }
				                                                        if (message.getSessionId().equals(receiverid))
				                                                        {
					                                                        MsgListItem item = new MsgListItem(message);
					                                                        items.add(item);
					                                                        addedListItems.add(item);
					                                                        needRefresh = true;
				                                                        }
			                                                        }
			                                                        if (needRefresh)
			                                                        {
				                                                        adapter.notifyDataSetChanged();
			                                                        }

			                                                        lastShowTimeItem = updateShowTimeItem(addedListItems, lastShowTimeItem);

			                                                        // incoming messages tip
			                                                        IMMessage lastMsg = messages.get(messages.size() - 1);
			                                                        if (lastMsg.getSessionId().equals(receiverid))
			                                                        {
				                                                        showIncomingMessageTip(lastMsg, needScrollToBottom);
			                                                        }
		                                                        }
	                                                        };
	Observer<IMMessage>			 messageStatusObserver		= new Observer<IMMessage>()
	                                                        {
		                                                        @Override
		                                                        public void onEvent(IMMessage message) {
			                                                        if (!message.getSessionId().equals(receiverid)) { return; }

			                                                        int index = getItemIndex(message.getUuid());
			                                                        if (index >= 0 && index < items.size())
			                                                        {
				                                                        MsgListItem item = items.get(index);
				                                                        item.getMessage().setStatus(message.getStatus());
				                                                        item.getMessage().setAttachStatus(message.getAttachStatus());
				                                                        refreshViewHolderByIndex(index);
			                                                        }
		                                                        }
	                                                        };
	Observer<AttachmentProgress> attachmentProgressObserver	= new Observer<AttachmentProgress>()
	                                                        {
		                                                        @Override
		                                                        public void onEvent(AttachmentProgress progress) {
			                                                                                                                                                                          /*
			                                                                                                                                                                           * Toast.
			                                                                                                                                                                           * makeText(
			                                                                                                                                                                           * AbsBaseMessageActivity
			                                                                                                                                                                           * .this,
			                                                                                                                                                                           * "msgId: "
			                                                                                                                                                                           * +
			                                                                                                                                                                           * progress
			                                                                                                                                                                           * .getKey
			                                                                                                                                                                           * (
			                                                                                                                                                                           * )
			                                                                                                                                                                           * +
			                                                                                                                                                                           * " progress: "
			                                                                                                                                                                           * +
			                                                                                                                                                                           * progress.
			                                                                                                                                                                           * getTransferred
			                                                                                                                                                                           * ()
			                                                                                                                                                                           * +
			                                                                                                                                                                           * "/"
			                                                                                                                                                                           * +
			                                                                                                                                                                           * progress
			                                                                                                                                                                           * .getTotal(
			                                                                                                                                                                           * ),
			                                                                                                                                                                           * Toast.
			                                                                                                                                                                           * LENGTH_SHORT
			                                                                                                                                                                           * )
			                                                                                                                                                                           * .
			                                                                                                                                                                           * show
			                                                                                                                                                                           * (
			                                                                                                                                                                           * )
			                                                                                                                                                                           * ;
			                                                                                                                                                                           */
			                                                        int index = getItemIndex(progress.getUuid());
			                                                        if (index >= 0 && index < items.size())
			                                                        {
				                                                        MsgListItem item = items.get(index);
				                                                        item.progress = (float) progress.getTransferred() / (float) progress.getTotal();
				                                                        refreshViewHolderByIndex(index);
			                                                        }
		                                                        }
	                                                        };
	Observer<CustomNotification> commandObserver			= new Observer<CustomNotification>()
	                                                        {
		                                                        @Override
		                                                        public void onEvent(CustomNotification message) {
			                                                        if (!message.getSessionId().equals(receiverid) || message.getSessionType() != getSessionTypeEnum()) { return; }
			                                                        onCommandMessage(message);
		                                                        }
	                                                        };
	private OnClickListener l = new OnClickListener()
	{

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
				case R.id.common_header_back:
					finish();
					break;
				case R.id.common_header_persion:
					titleView.clickRightbutton(receiverid);

					//					TeamInfoActivity.startForTeamInfo(context, receiverid);
					break;
				default:
					break;
			}
		}
	};

	// abs method
	protected abstract int getResId();

	protected abstract SessionTypeEnum getSessionTypeEnum();

	protected abstract void showIncomingMessageTip(IMMessage newMessage, boolean needScrollToBottom); // 收到消息提示用户

	/**
	 * @param titleView
	 *            the titleView to set
	 */
	public void setTitleView(TitleView titleView) {
		this.titleView = titleView;
	}

	/**
	 * ***************************** life cycle *******************************
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		rootView = LayoutInflater.from(this).inflate(getResId(), null);
		setContentView(rootView);

		context = this;
		uiHandler = Handlers.sharedHandler(this);
		contactHttpClient = ContactHttpClient.getInstance();

		onParseIntent();
		initActionBar();
		initAdapter();
		initListView();

		resetMessageLoadStatus();
		loadMessageFromDB(LOAD_MESSAGE_COUNT, true);

		registerObservers(true);
	}

	@Override
	protected void onPause() {
		super.onPause();

		NIMClient.getService(MsgService.class).setChattingAccount(MsgService.MSG_CHATTING_ACCOUNT_NONE, SessionTypeEnum.None);
	}

	@Override
	protected void onResume() {
		super.onResume();

		NIMClient.getService(MsgService.class).setChattingAccount(receiverid, getSessionTypeEnum());
		NIMClient.getService(MsgServiceObserve.class).observeCustomNotification(commandObserver, true);
	}

	@Override
	protected void onStop() {
		super.onStop();
		NIMClient.getService(MsgServiceObserve.class).observeCustomNotification(commandObserver, false);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();

		registerObservers(false);
	}

	public void setTitle(String title) {
		if (null != titleTView)
		                        titleTView.setText(title);
	}

	/**
	 * ***************************** init *******************************
	 */

	protected void onParseIntent() {
		receiverid = getIntent().getStringExtra(Extras.EXTRA_ACCOUNT);
		setTitle(ContactDataCache.getInstance().getBuddyDisplayName(receiverid));
	}

	protected void initActionBar() {
		backBtn = (Button) findViewById(R.id.common_header_back);
		backBtn.setVisibility(View.VISIBLE);
		backBtn.setOnClickListener(l);
		titleTView = (TextView) findViewById(R.id.common_header_name);
		groupBtn = (ImageView) findViewById(R.id.common_header_persion);
		groupBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.message_actionbar_right_icon));
		groupBtn.setVisibility(View.VISIBLE);
		groupBtn.setOnClickListener(l);
	}

	protected void initAdapter() {
		adapter = new MsgAdapter(this, items, this);
		adapter.setEventListener(this);
	}

	private void initListView() {
		messageListView = (MessageListView) findViewById(R.id.messageListView);
		messageListView.requestDisallowInterceptTouchEvent(true);
		messageListView.setMode(AutoRefreshListView.Mode.START);
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
		{
			messageListView.setOverScrollMode(View.OVER_SCROLL_NEVER);
		}
		// listener
		messageListView.setOnRefreshListener(this);
		messageListView.setListViewEventListener(this);
		// adapter
		messageListView.setAdapter(adapter);
	}

	/**
	 * *************** implements TAdapterDelegate ***************
	 */
	@Override
	public int getViewTypeCount() {
		return adapter.getViewTypeCount();
	}

	@SuppressWarnings ("unchecked")
	@Override
	public Class<? extends TViewHolder> viewHolderAtPosition(int position) {
		return adapter.getViewHolderByType(items.get(position).getViewHolderType());
	}

	@Override
	public boolean enabled(int position) {
		return false;
	}

	/**
	 * *************** OnRefreshListener ***************
	 */
	@Override
	public void onRefreshFromStart() {
		loadMessageFromDB(LOAD_MESSAGE_COUNT, true); // load old data
	}

	@Override
	public void onRefreshFromEnd() {
	}

	/**
	 * *************** ViewHolderEventListener ***************
	 */
	@Override
	public void onResendButtonPressed(IMMessage resendMessage) {
		resendMessage(resendMessage); // 重发
	}

	@Override
	public void onRedownloadButtonPressed(IMMessage message) {
		showRedownloadConfirmDlg(message); // 重新下载
	}

	@Override
	public void onHeadImagePressed(Object item) {
	}

	/**
	 * ********************** load/sort message *****************************
	 */

	public void resetMessageLoadStatus() {
		firstLoadMessageHistory = true;

		items.clear();
		refreshMessageList();
	}

	/**
	 * 加载历史消息
	 *
	 * @param maxResultsCount
	 *            最多加载多少条
	 * @param needOffset
	 *            是否ListView自动偏移
	 */
	protected void loadMessageFromDB(final int maxResultsCount, final boolean needOffset) {
		NIMClient.getService(MsgService.class).queryMessageList(receiverid, getSessionTypeEnum(), items.size(), maxResultsCount).setCallback(new RequestCallback<List<IMMessage>>() {
			@Override
			public void onSuccess(List<IMMessage> msgList) {
				boolean first = firstLoadMessageHistory;
				firstLoadMessageHistory = false;
				if (msgList != null) {
					onMessageLoaded(msgList, first, LOAD_MESSAGE_COUNT, needOffset);

				}
			}

			@Override
			public void onFailed(int code) {

			}

			@Override
			public void onException(Throwable exception) {

			}
		});

	}

	private void onMessageLoaded(List<IMMessage> loadedMsgList, boolean first, int requestCount, boolean needOffset) {
		int count = loadedMsgList.size();

		List<MsgListItem> addedMessageListItems;
		if (loadedMsgList.size() > 0)
		{
			// add data and refresh listView
			addedMessageListItems = addOlderListToMessageList(loadedMsgList);
			count = addedMessageListItems.size();

			// 加载旧消息时lastShowTimeItem置为null，确保加载到的第一条总是可以显示时间
			MsgListItem item = updateShowTimeItem(addedMessageListItems, null);
			// 如果是第一次加载，updateShowTimeItem返回的就是lastShowTimeItem
			if (first)
			{
				lastShowTimeItem = item;
			}
			else {
				for (int i = 0; i < addedMessageListItems.size(); i++) {
					items.add(addedMessageListItems.get(i));
				}

			}
			MsgViewHolderPictureRight.messageItems2.clear();
			MsgViewHolderPictureLeft.messageItems2.clear();
			MsgViewHolderPictureRight.map.clear();
			MsgViewHolderPictureLeft.map.clear();

			for (int i = 0; i < items.size(); i++)
			{
				if (items.get(i).getMessage().getAttachment() != null && (items.get(i).getViewHolderType() == MsgViewHolderType.PICTURE_RIGHT || items.get(i).getViewHolderType() == MsgViewHolderType.PICTURE_LEFT))
				{
					//				String url = ((ImageAttachment) messageItems.get(i).getMessage().getAttachment()).getPath();
					//				urlList.add(url);
					MsgViewHolderPictureRight.messageItems2.add(items.get(i));
					MsgViewHolderPictureRight.map.put(i, MsgViewHolderPictureRight.messageItems2.size() - 1);
					MsgViewHolderPictureLeft.messageItems2.add(items.get(i));
					MsgViewHolderPictureLeft.map.put(i, MsgViewHolderPictureLeft.messageItems2.size() - 1);
				}

			}
		}

		// 第一次加载后需要定位
		if (first)
		{
			ListViewUtil.scrollToBottom(messageListView);
		}

		messageListView.onRefreshComplete(count, requestCount, needOffset);
	}

	private List<MsgListItem> addOlderListToMessageList(List<IMMessage> messages) {

		removeDuplication(messages);

		List<MsgListItem> addMessageListItems = new ArrayList<MsgListItem>();
		for (IMMessage messageHistory : messages)
		{
			MsgListItem item = new MsgListItem(messageHistory);
			addMessageListItems.add(0, item);
			items.add(0, item);
		}

		refreshMessageList();

		return addMessageListItems;
	}

	private void removeDuplication(List<IMMessage> messages) {
		if (items.size() == 0 || messages.size() == 0) { return; }

		IMMessage msg = items.get(0).getMessage();
		// 先去除交叉的部分
		while (messages.size() > 0)
		{
			if (messages.get(0).getTime() > msg.getTime())
			{
				messages.remove(0);
			}
			else
			{
				break;
			}
		}

		if (messages.size() == 0) { return; }

		// 如果顺序已经是对的了
		if (messages.get(0).getTime() < msg.getTime()) { return; }

		// 顶多就是时间相等的了
		for (IMMessage message : messages)
		{
			for (MsgListItem item : items)
			{
				if (message.getTime() != item.getMessage().getTime())
				{
					continue;
				}
			}
			if (message.isTheSame(msg))
			{
				items.remove(items);
				continue;
			}
		}
	}

	private MsgListItem updateShowTimeItem(List<MsgListItem> items, MsgListItem lastShowTimeItem) {
		for (MsgListItem messageListItem : items)
		{
			if (setShowTimeFlag(messageListItem, lastShowTimeItem))
			{
				lastShowTimeItem = messageListItem;
			}
		}

		return lastShowTimeItem;
	}

	private boolean setShowTimeFlag(MsgListItem item, MsgListItem lastShowTimeItem) {
		boolean update = false;

		IMMessage messageHistory = item.getMessage();
		if (item.hideTimeAlways())
		{
			item.needShowTime = false;
		}
		else
		{
			if (lastShowTimeItem == null)
			{
				item.needShowTime = true;
				update = true;
			}
			else
			{
				long time = lastShowTimeItem.getMessage().getTime();
				long now = messageHistory.getTime();

				if (now - time < (long) (5 * 60 * 1000))
				{
					item.needShowTime = false;
				}
				else
				{
					item.needShowTime = true;
					update = true;
				}
			}
		}

		return update;
	}
															
	/**
	 * ************************* send/recv messages
	 * ********************************
	 */

	private void registerObservers(boolean register) {
		MsgServiceObserve service = NIMClient.getService(MsgServiceObserve.class);
		service.observeReceiveMessage(incomingMessageObserver, register);
		service.observeMsgStatus(messageStatusObserver, register);
		service.observeAttachmentProgress(attachmentProgressObserver, register);
	}
															
	// 是否允许发送消息
	protected boolean isAllowSendMessage(final IMMessage message) {
		return true;
	}
	
	// 发送文本消息
	protected void sendTextMessage(String content) {
		IMMessage textMessage = MessageBuilder.createTextMessage(receiverid, getSessionTypeEnum(), content);
		sendMessage(textMessage);
	}
	
	// 发送图片消息
	protected void sendImageMessage(String toId, SessionTypeEnum sessionType, File file, boolean isOrig) {
		IMMessage imageMessage = MessageBuilder.createImageMessage(toId, sessionType, file, file.getName());
		sendMessage(imageMessage);
	}
	
	// 发送语音消息
	protected void sendAudioMessage(String toId, SessionTypeEnum sessionType, File file, long duration) {
		IMMessage audioMessage = MessageBuilder.createAudioMessage(toId, sessionType, file, duration);
		sendMessage(audioMessage);
	}
	
	// 发送视频消息
	protected void sendVideoMessage(String toId, SessionTypeEnum sessionType, File file, long duration, int width, int height, String md5) {
		IMMessage videoMessage = MessageBuilder.createVideoMessage(toId, sessionType, file, duration, width, height, md5);
		sendMessage(videoMessage);
	}
	
	// 发送地理信息消息
	protected void sendLocationMessage(double latitude, double longitude, String address) {
		IMMessage messageHistory = MessageBuilder.createLocationMessage(receiverid, getSessionTypeEnum(), latitude, longitude, address);
		sendMessage(messageHistory);
	}
	
	// 发送文件消息
	protected void sendFileMessage(String toId, SessionTypeEnum sessionType, File file) {
		IMMessage fileMessage = MessageBuilder.createFileMessage(toId, sessionType, file, file.getName());
		sendMessage(fileMessage);
	}
	
	// 发送消息到服务器
	protected void sendMessage(final IMMessage message) {
		if (!isAllowSendMessage(message)) { return; }
		
		// send message to server and save to db
		NIMClient.getService(MsgService.class).sendMessage(message, false);
		
		// add to listView and refresh
		MsgListItem item = new MsgListItem(message);
		items.add(item);
		List<MsgListItem> addedListItems = new ArrayList<MsgListItem>(1);
		addedListItems.add(item);
		lastShowTimeItem = updateShowTimeItem(addedListItems, lastShowTimeItem);
		
		adapter.notifyDataSetChanged();
		ListViewUtil.scrollToBottom(messageListView);
	}
	
	// 重发消息到服务器
	protected void resendMessage(IMMessage message) {
		// 重置状态为unsent
		int index = getItemIndex(message.getUuid());
		if (index >= 0 && index < items.size())
		{
			MsgListItem item = items.get(index);
			item.getMessage().setStatus(MsgStatusEnum.sending);
			refreshViewHolderByIndex(index);
		}
		
		NIMClient.getService(MsgService.class).sendMessage(message, true);
	}
	
	// 重新下载(对话框提示)
	protected void showRedownloadConfirmDlg(final IMMessage message) {
		EasyAlertDialogHelper.OnDialogActionListener listener = new EasyAlertDialogHelper.OnDialogActionListener()
		{
			
			@Override
			public void doCancelAction() {
			}
			
			@Override
			public void doOkAction() {
				NIMClient.getService(MsgService.class).downloadAttachment(message, true);
			}
		};
		
		final EasyAlertDialog dialog = EasyAlertDialogHelper.createOkCancelDiolag(this, null, getString(R.string.repeat_download_message), true, listener);
		dialog.show();
	}
	
	protected void refreshMessageList() {
		runOnUiThread(new Runnable()
		{
			
			@Override
			public void run() {
				adapter.notifyDataSetChanged();
			}
		});
	}
	
	protected void refreshViewHolderByIndex(final int index) {
		runOnUiThread(new Runnable()
		{
			
			@Override
			public void run() {
				if (index < 0) { return; }
				
				Object tag = ListViewUtil.getViewHolderByIndex(messageListView, index);
				if (tag instanceof MsgViewHolder)
				{
					MsgViewHolder viewHolder = (MsgViewHolder) tag;
					viewHolder.refreshCurrentItem();
				}
			}
		});
	}
	
	protected int getItemIndex(String uuid) {
		for (int i = 0; i < items.size(); i++)
		{
			MsgListItem item = items.get(i);
			if (TextUtils.equals(item.getMessage().getUuid(), uuid)) { return i; }
		}
		
		return -1;
	}
	
	private void onCommandMessage(CustomNotification message) {
		String content = message.getContent();
		try
		{
			JSONObject json = JSON.parseObject(content);
			int id = json.getIntValue("id");
			if (id == 1)
			{
				// 正在输入
				//				Toast.makeText(this, "对方正在输入...", Toast.LENGTH_LONG).show();
			}
			else
			{
				//				Toast.makeText(this, "command: " + content, Toast.LENGTH_SHORT).show();
			}
			
		}
		catch (Exception e)
		{
		
		}
	}
	
	@Override
	protected void onActivityResult(int arg0, int arg1, Intent arg2) {
		super.onActivityResult(arg0, arg1, arg2);
	}
	
	public interface TitleView
	{
		void clickRightbutton(String receiverid);
	}
}
